/*
 * Copyright 2010 Francisco Modesto
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.googlecode.gwt.tinyaop.rebind;

public enum Constants {
  BOOLEAN {
    public void toJava(Object object, StringBuilder sb) {
      boolean value = (Boolean) object;
      sb.append(value? "true" : "false");
    }
    
    public void toJavaArray(Object object, StringBuilder sb) {
      boolean[] values = (boolean[]) object;
      sb.append("{");
      for (int i = 0; i < values.length; i++) {
        if (i != 0) {
          sb.append(", ");
        }
        toJava(values[i], sb);
      }
      sb.append("}");
    }
    
    public boolean isType(Object object) {
      Class<? extends Object> type = object.getClass();
      return type == boolean.class || type == Boolean.class;
    }

    public boolean isTypeArray(Object object) {
      return object.getClass() == boolean[].class;
    }
  },
  BYTE {
    public void toJava(Object object, StringBuilder sb) {
      byte value = (Byte) object;
      sb.append("0x" + Integer.toHexString(value));
    }
    
    public void toJavaArray(Object object, StringBuilder sb) {
      byte[] values = (byte[]) object;
      sb.append("{");
      for (int i = 0; i < values.length; i++) {
        if (i != 0) {
          sb.append(", ");
        }
        toJava(values[i], sb);
      }
      sb.append("}");
    }
    
    public boolean isType(Object object) {
      Class<? extends Object> type = object.getClass();
      return type == byte.class || type == Byte.class;
    }

    public boolean isTypeArray(Object object) {
      return object.getClass() == byte[].class;
    }
  },
  CHAR {
    public void toJava(Object object, StringBuilder sb) {
      char value = (Character) object;
      sb.append("0x" + Integer.toHexString(value));
    }
    
    public void toJavaArray(Object object, StringBuilder sb) {
      char[] values = (char[]) object;
      sb.append("{");
      for (int i = 0; i < values.length; i++) {
        if (i != 0) {
          sb.append(", ");
        }
        toJava(values[i], sb);
      }
      sb.append("}");
    }
    
    public boolean isType(Object object) {
      Class<? extends Object> type = object.getClass();
      return type == char.class || type == Character.class;
    }

    public boolean isTypeArray(Object object) {
      return object.getClass() == char[].class;
    }
  },
  SHORT {
    public void toJava(Object object, StringBuilder sb) {
      short value = (Short) object;
      sb.append("0x" + Integer.toHexString(value));
    }
    
    public void toJavaArray(Object object, StringBuilder sb) {
      short[] values = (short[]) object;
      sb.append("{");
      for (int i = 0; i < values.length; i++) {
        if (i != 0) {
          sb.append(", ");
        }
        toJava(values[i], sb);
      }
      sb.append("}");
    }
    
    public boolean isType(Object object) {
      Class<? extends Object> type = object.getClass();
      return type == short.class || type == Short.class;
    }

    public boolean isTypeArray(Object object) {
      return object.getClass() == short[].class;
    }
  },
  INT {
    public void toJava(Object object, StringBuilder sb) {
      int value = (Integer) object;
      sb.append("0x" + Integer.toHexString(value));
    }
    
    public void toJavaArray(Object object, StringBuilder sb) {
      int[] values = (int[]) object;
      sb.append("{");
      for (int i = 0; i < values.length; i++) {
        if (i != 0) {
          sb.append(", ");
        }
        toJava(values[i], sb);
      }
      sb.append("}");
    }
    
    public boolean isType(Object object) {
      Class<? extends Object> type = object.getClass();
      return type == int.class || type == Integer.class;
    }

    public boolean isTypeArray(Object object) {
      return object.getClass() == int[].class;
    }
  },
  FLOAT {
    public void toJava(Object object, StringBuilder sb) {
      int value = Float.floatToRawIntBits((Float) object);
      sb.append("Float.intBitsToFloat(").append(toJava(value)).append(")");
    }
    
    public void toJavaArray(Object object, StringBuilder sb) {
      float[] values = (float[]) object;
      sb.append("{");
      for (int i = 0; i < values.length; i++) {
        if (i != 0) {
          sb.append(", ");
        }
        toJava(values[i], sb);
      }
      sb.append("}");
    }
    
    public boolean isType(Object object) {
      Class<? extends Object> type = object.getClass();
      return type == float.class || type == Float.class;
    }

    public boolean isTypeArray(Object object) {
      return object.getClass() == float[].class;
    }
  },
  LONG {
    public void toJava(Object object, StringBuilder sb) {
      long value = (Long) object;
      sb.append("0x").append(Long.toHexString(value)).append("L");
    }
    
    public void toJavaArray(Object object, StringBuilder sb) {
      long[] values = (long[]) object;
      sb.append("{");
      for (int i = 0; i < values.length; i++) {
        if (i != 0) {
          sb.append(", ");
        }
        toJava(values[i], sb);
      }
      sb.append("}");
    }
    
    public boolean isType(Object object) {
      Class<? extends Object> type = object.getClass();
      return type == long.class || type == Long.class;
    }

    public boolean isTypeArray(Object object) {
      return object.getClass() == long[].class;
    }
  },
  DOUBLE {
    public void toJava(Object object, StringBuilder sb) {
      long value = Double.doubleToRawLongBits((Double) object);
      sb.append("Double.longBitsToDouble(").append(toJava(value)).append(")");
    }
    
    public void toJavaArray(Object object, StringBuilder sb) {
      double[] values = (double[]) object;
      sb.append("{");
      for (int i = 0; i < values.length; i++) {
        if (i != 0) {
          sb.append(", ");
        }
        toJava(values[i], sb);
      }
      sb.append("}");
    }
    
    public boolean isType(Object object) {
      Class<? extends Object> type = object.getClass();
      return type == double.class || type == Double.class;
    }

    public boolean isTypeArray(Object object) {
      return object.getClass() == double[].class;
    }
  },
  STRING {
    public void toJava(Object object, StringBuilder sb) {
      String value = (String) object;
      sb.append('"').append(value).append('"');
    }
    
    public void toJavaArray(Object object, StringBuilder sb) {
      String[] values = (String[]) object;
      sb.append("{");
      for (int i = 0; i < values.length; i++) {
        if (i != 0) {
          sb.append(", ");
        }
        toJava(values[i], sb);
      }
      sb.append("}");
    }
    
    public boolean isType(Object object) {
      return object.getClass() == String.class;
    }

    public boolean isTypeArray(Object object) {
      return object.getClass() == String[].class;
    }
  },
  ENUM {
    public void toJava(Object object, StringBuilder sb) {
      Enum<?> value = (Enum<?>) object;
      sb.append(value.getClass().getCanonicalName()).append(".").append(value.name());
    }
    
    public void toJavaArray(Object object, StringBuilder sb) {
      Enum<?>[] values = (Enum<?>[]) object;
      sb.append("{");
      for (int i = 0; i < values.length; i++) {
        if (i != 0) {
          sb.append(", ");
        }
        toJava(values[i], sb);
      }
      sb.append("}");
    }
    
    public boolean isType(Object object) {
      return object.getClass().isEnum();
    }

    public boolean isTypeArray(Object object) {
      Class<? extends Object> type = object.getClass();
      return type.isArray() && type.getComponentType().isEnum();
    }
  };

  public abstract void toJava(Object object, StringBuilder sb);
  public abstract void toJavaArray(Object object, StringBuilder sb);
  public abstract boolean isType(Object value);
  public abstract boolean isTypeArray(Object value);
  
  public static String toJava(Object o) {
    StringBuilder sb = new StringBuilder();
    deepToJava(o, sb);
    return sb.toString();
  }

  private static void deepToJava(Object object, StringBuilder sb) {
    for (Constants c : values()) {
      if (c.isType(object)) {
        c.toJava(object, sb);
        return;
      }
      else if (c.isTypeArray(object)) {
        c.toJavaArray(object, sb);
        return;
      }
    }
    arrayOfArraysToJava(object, sb);
  }
  
  private static void arrayOfArraysToJava(Object object, StringBuilder sb) {
    sb.append("{");
    Object[] values = (Object[]) object;
    for (int i = 0; i < values.length; i++) {
      if (i != 0) {
        sb.append(", ");
      }
      deepToJava(values[i], sb);
    }
    sb.append("}");
    return;
  }
}
